import React, { useCallback } from 'react';
import { useDrop } from 'react-dnd';
import update from 'immutability-helper';
import { connect } from 'dva';
import ScrollBar from '@/components/ScrollBar';
import { getUniqueID } from '@/utils/utils';
import { getLevel, pickLast, getNode, getAction, $$set } from './utils';
import SlickForm from './SlickForm';
import { itemTypes } from './types';

const Canvas = ({
  formSchema,
  vertical,
  columnNum,
  labelWidth,
  linkages,
  submitUrl,
  saveUrl,
  needBack,
  needSave,
  needSubmit,
  showHideItem,
  dispatch,
}) => {
  // 第一个参数是 collect 方法返回的对象，第二个参数是一个 ref 值，赋值给 drop 元素
  const [{ isOver, canDrop, item, isOverCurrent }, drop] = useDrop({
    // accept 是一个标识，需要和对应的 drag 元素中 item 的 type 值一致，否则不能感应
    accept: [itemTypes.bowl, itemTypes.block, itemTypes.staticBlock],
    // spec: {
    //   canDrag(props, monitor) {
    //     // console.log(props);
    //   },
    // },
    // // drag 组件拖拽结束后，放到 drop 组件时触发，返回的值会作为参数传递给 drag 组件 end 方法的第一个参数
    // drop(item, monitor) {
    //   const didDrop = monitor.didDrop();
    //   if (didDrop && !greedy) {
    //     return;
    //   }
    //   setHasDropped(true);
    //   // setHasDroppedOnChild(didDrop);
    // },
    // drag 组件在 drop 组件上方 hover 时触发
    // hover(props, monitor, component) {
    //   // console.group('canvas hover');
    //   // console.log(props, monitor);
    //   // console.groupEnd('canvas hover');
    // },
    // // collect 函数，返回的对象会成为 useDrop 的第一个参数，可以在组件中直接进行使用
    // collect: monitor => ({
    //   isOver: monitor.isOver(),
    //   canDrop: monitor.canDrop(),
    //   item: monitor.getItem(),
    //   isOverCurrent: monitor.isOver({ shallow: true }),
    // }),
  });

  const moveItem = useCallback(
    (dragLevel, hoverLevel, dragItem, hoverItem, name) => {
      // console.log('dragLevel', dragLevel, hoverLevel, name);
      /**
       * 负责拖拽时，元素的位置切换
       * 1、dragLevel 为 undefined，表示当前鼠标拖拽的是 Left 中的组件
       * 2、dragLevel 不为 undefined，表示当前当前鼠标拖拽的是**画布**中的组件
       */
      if (dragLevel === undefined) {
        const holderLevel = getLevel(formSchema, { __id: 'holder' });

        // 如果当前鼠标拖拽的组件 hover在holder组件上，不做任何操作
        if (`${hoverLevel}` === `${holderLevel}`.split('-')[0]) {
          return;
        }

        if (holderLevel !== -1) {
          let insertItem = {
            componentType: dragItem.componentType,
            __id: 'holder',
            label: dragItem.label,
            name: getUniqueID(dragItem.componentType),
          };

          if (dragItem.type === itemTypes.bowl) {
            insertItem = { ...insertItem, properties: [] };
          }

          if (dragItem.type === itemTypes.bowl) {
            dispatch({
              type: 'formDesigner/updateFormSchema',
              payload: update(
                update(
                  formSchema,
                  getAction(holderLevel, { $splice: [[pickLast(holderLevel), 1]] })
                ),
                getAction(hoverLevel, { $splice: [[pickLast(hoverLevel), 0, insertItem]] })
              ),
            });
          }

          // 塞到目标bowl的最后一位
          if (dragItem.type === itemTypes.food) {
            dispatch({
              type: 'formDesigner/updateFormSchema',
              payload: update(
                update(
                  formSchema,
                  getAction(holderLevel, { $splice: [[pickLast(holderLevel), 1]] })
                ),
                { [hoverLevel]: { properties: { $push: [insertItem] } } }
              ),
            });
          }
          // dispatch({
          //   type: 'formDesigner/updateFormSchema',
          //   payload: update(formSchema, {
          //     $splice: [
          //       [holderLevel, 1],
          //       [
          //         hoverLevel,
          //         0,
          //         {
          //           'componentType': dragItem.componentType,
          //           __id: 'holder',
          //           label: dragItem.label,
          //           name: getUniqueID(dragItem.componentType),
          //           properties: [],
          //         },
          //       ],
          //     ],
          //   }),
          // });
        }
      } else {
        const dragCard = getNode(formSchema, dragLevel);
        const hoverCard = getNode(formSchema, hoverLevel);

        if (dragCard !== undefined && hoverLevel !== -1) {
          dispatch({
            type: 'formDesigner/updateFormSchema',
            payload: $$set($$set(formSchema, dragLevel, hoverCard), hoverLevel, dragCard),
          });

          // dispatch({
          //   type: 'formDesigner/updateFormSchema',
          //   payload: update(formSchema, {
          //     $splice: [
          //       [dragLevel, 1],
          //       [hoverLevel, 0, dragCard],
          //     ],
          //   }),
          // });
        }
      }
      // eslint-disable-next-line
    },
    [formSchema, dispatch]
  );

  return (
    <div ref={drop}>
      <ScrollBar
        autoHeight={false}
        renderView={({ style, ...props }) => {
          const viewStyle = {
            padding: '24px 16px',
          };
          return <div style={{ ...style, ...viewStyle }} {...props} />;
        }}
      >
        <SlickForm
          formSchema={formSchema}
          moveItem={moveItem}
          mode="edit"
          vertical={vertical}
          columnNum={columnNum}
          labelWidth={labelWidth}
          linkages={linkages}
          submitUrl={submitUrl}
          saveUrl={saveUrl}
          needSave={needSave}
          needSubmit={needSubmit}
          needBack={needBack}
          showHideItem={showHideItem}
        />
      </ScrollBar>
    </div>
  );
};

export default connect(({ formDesigner }) => ({
  formSchema: formDesigner.formSchema,
  current: formDesigner.current,
  vertical: formDesigner.vertical,
  labelWidth: formDesigner.labelWidth,
  columnNum: formDesigner.columnNum,
  linkages: formDesigner.linkages,
  submitUrl: formDesigner.submitUrl,
  saveUrl: formDesigner.saveUrl,
  needSubmit: formDesigner.needSubmit,
  needSave: formDesigner.needSave,
  needBack: formDesigner.needBack,
  showHideItem: formDesigner.showHideItem,
}))(Canvas);
